function [f] = ObjValue(x, Problem)
%ObjValue: Objective Function
%   x: ~ -by- d matrix, decision variables
%   f: ~ -by 1 vector, objective function values
%   Problem.FuncType
%          .dimension
%          .k (for modified Rastrigin function)
%          .BaseFunc: the id of the base function combinatioin
%              (for composition function): 1, 2, 3, 4
%          .o: the set of optimal solution (for composition function)
%          .M: the rotatioin matrix (for composition function)
%% ALL GLOBAL OPTIMA
if strcmp(Problem.FuncType,'EqualMinima')
    %% one-dimensional equal minima
    f = 1-sin(5.*pi.*x).^6;
elseif strcmp(Problem.FuncType,'Himmelblau')
    %% Himmelblau's function
    f = (x(:,1).^2+x(:,2)-11).^2+(x(:,1)+x(:,2).^2-7).^2;
elseif strcmp(Problem.FuncType,'Sixhump')
    %% Six-hump camel back
    f = 4.*((4-2.1.*(x(:,1).^2)+x(:,1).^4./3).*(x(:,1).^2)+x(:,1).*x(:,2)+(4.*(x(:,2).^2)-4).*(x(:,2).^2));
elseif strcmp(Problem.FuncType,'ModifiedRastrigin')
    %% Modified Rastrigin function
    k = Problem.k;
    xn = size(x,1);
    f = sum(10+9.*cos(2.*pi.*repmat(k,[xn,1]).*x),2);
elseif strcmp(Problem.FuncType,'Vincent')
    %% Vincent function
    f = 1-mean(sin(10.*log(x)),2);
elseif strcmp(Problem.FuncType,'Shubert')
    %% Shubert function
    [xn,d] = size(x);
    f = zeros(xn,1);
    a = repmat((1:5)',[1,d]);
    for i = 1:xn 
        f(i) = prod(sum(a.*cos(repmat(x(i,:),[5,1]).*(a+1)+a),1));
    end
elseif strcmp(Problem.FuncType,'Composition')
    %% Conposition function
    [xn,d] = size(x);
    o = Problem.o;
    M = Problem.M;
    % 1: Sphere; 2: Grienwank; 3: Rastrigin; 4: Weierstrass; 5:EF8F2
    if Problem.BaseFunc == 1
        % Composition functions 1
        fun_type = [2,2,4,4,1,1];
        sigma = [1,1,1,1,1,1];
        lambda = [1,1,8,8,1/5,1/5];
    elseif Problem.BaseFunc == 2
        % Composition functions 2
        fun_type = [3,3,4,4,2,2,1,1];
        sigma = [1,1,1,1,1,1,1,1];
        lambda = [1,1,10,10,1/10,1/10,1/7,1/7];
    elseif Problem.BaseFunc == 3
        % Composition functions 3
        fun_type = [5,5,4,4,2,2];
        sigma = [1,1,2,2,2,2];
        lambda = [1/4,1/10,2,1,2,5];
    elseif Problem.BaseFunc == 4
        % Composition functions 4
        fun_type = [3,3,5,5,4,4,2,2];
        sigma = [1,1,1,1,1,2,2,2];
        lambda = [4,1,4,1,1/10,1/5,1/10,1/40];
    end
    n = length(fun_type);
    bias = zeros(1,n);
    % weights
    w = zeros(xn,n);
    for i = 1:xn
        w(i,:) = (exp(-sum((repmat(x(i,:),[n,1])-o).^2,2)./2./d./(sigma.^2)'))';
    end
    [maxw,wid] = max(w,[],2);
    w = w.*(1-repmat(maxw,[1,n]).^10);
    for i = 1:xn
        w(i,wid(i)) = maxw(i);
    end
    w = w./repmat(sum(w,2),[1,n]);
    % objective function
    fbasic = zeros(xn,n);
    for i = 1:n
        fbasic0 = fcom(fun_type(i),(x-repmat(o(i,:),[xn,1]))./lambda(i)*M(:,:,i));
        f_max = abs(fcom(fun_type(i),(ones(1,d).*5)./lambda(i)*M(:,:,i)));
        fbasic0 = fbasic0.*2000./f_max;
        fbasic(:,i) = (fbasic0 + bias(i));
    end
    f = sum(w.*fbasic,2);

%% MANY LOCAL OPTIMA
elseif strcmp(Problem.FuncType,'IncreasingMinima')
    %% one-dimensional increasing minima
    f = 1-exp(-2.*log(2).*((x-0.08)./0.854).^2).*(sin(5.*pi.*(x.^(3/4)-0.05)).^6);
elseif strcmp(Problem.FuncType,'Rastrigin')
    %% Rastrigin function
    d = size(x,2);
    A = 10;
    f = A*d+sum(x.^2-A.*cos(2.*pi.*x),2);

%% CONTINUOUS OPTIMA PROBLEMS
elseif strcmp(Problem.FuncType,'Schaffer')
    %% Schaffer's function
    f = 0.5+(sin(sqrt(sum(x.^2,2))).^2-0.5)./((1+0.001.*(sum(x.^2,2))).^2);
    %% Michalewicz
    % f = -sin(x(:,1)).*(sin(x(:,1).^2./pi).^20)+sin(x(:,2)).*(sin(x(:,2).^2.*2./pi).^20);
    % % d = 2;
    % % x_bound = repmat([0,pi],[d,1]);
else 
    error('No such function found.')
end
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% basic functions for composition function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    function fcom = fcom(id,x)
%   id: 1: Sphere; 2: Grienwank; 3: Rastrigin; 4: Weierstrass; 5:EF8F2
        xn_f = size(x,1);
        if id == 1
            fcom = sum(x.^2,2);
        elseif id == 2
            fcom = sum(x.^2,2)./4000-prod(cos(x./repmat(sqrt(1:d),[xn_f,1])),2)+1;
        elseif id == 3
            fcom = sum(x.^2-10.*cos(2*pi.*x)+10,2);
        elseif id==4
            fcom = zeros(xn_f,1);
            kk = (0:20)';
            aa = 0.5.^kk;
            bb = 3.^kk;
            fw0 = d*sum(aa.*cos(2*pi.*bb.*0.5));
            aa = repmat(aa,[1,d]);
            bb = repmat(bb,[1,d]);
            for ii = 1:xn_f
                fcom(ii) = sum(sum(aa.*cos(2*pi.*bb.*(repmat(x(ii,:),[21,1])+0.5))))-fw0;
            end
        else
            x = x+1; % (1,...,1) is the minima
            F2x = (x.^2-x(:,[2:d,1])).^2.*100+(x-1).^2;
            fcom = sum(F2x.^2./4000-cos(F2x)+1,2);
        end
%         fcom = -fcom;
    end

end

